package com.xxr.mom.ci.charging.interworking.customize;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.xxr.mom.ci.charging.device.entity.Station;
import com.xxr.mom.ci.charging.interworking.base.InterfaceSender;
import com.xxr.mom.ci.charging.interworking.data.SynchronizeDeviceConnectorData;
import com.xxr.mom.ci.charging.interworking.data.SynchronizeDeviceData;
import com.xxr.mom.ci.charging.interworking.data.SynchronizeDeviceEquipmentData;
import com.xxr.mom.ci.charging.interworking.dto.InterworkingConfigDto;
import com.xxr.mom.ci.charging.interworking.entity.InterworkingConfig;
import com.xxr.mom.ci.charging.interworking.enums.MethodEnum;
import com.xxr.mom.ci.charging.interworking.enums.VersionEnum;
import com.xxr.mom.ci.charging.interworking.json.SynchronizeDeviceSchedule;
import com.xxr.mom.ci.charging.interworking.v2016.AbstractV2016Service;
import com.xxr.mom.ci.charging.interworking.vo.ConnectorInfo;
import com.xxr.mom.ci.charging.interworking.vo.EquipmentInfo;
import com.xxr.mom.ci.charging.interworking.vo.StationInfo;
import com.xxr.mom.ci.charging.interworking.vo.api.QueryEquipBusinessPolicyRequest;
import com.xxr.mom.ci.charging.interworking.vo.api.QueryEquipBusinessPolicyResponse;
import com.xxr.mom.ci.charging.interworking.vo.api.QueryStationsInfoRequest;
import com.xxr.mom.ci.charging.interworking.vo.api.QueryStationsInfoResponse;
import com.xxr.mom.ci.charging.mapper.device.StationMapper;
import com.xxr.mom.ci.charging.service.LogService;
import com.xxr.mom.ci.common.exception.BusinessException;
import com.xxr.mom.ci.common.log.LogTrace;
import com.xxr.mom.ci.common.util.Constant;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 同步设备信息，包括站点，桩，枪，计费等。
 *
 * @description: SynchronizeDeviceService
 * @date: 2024/8/19 23:24
 * @author: natsuki_kining
 * @version: 1.0
 */
@Log4j2
@Service
public class SynchronizeDeviceService extends AbstractV2016Service<QueryStationsInfoRequest, QueryStationsInfoResponse> implements InterfaceSender<QueryStationsInfoRequest, QueryStationsInfoResponse> {

    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private LogService logService;
    @Autowired(required = false)
    private RedisTemplate<String, SynchronizeDeviceSchedule> synchronizeDeviceScheduleRedisTemplate;
    @Autowired
    private Map<String, InterfaceSender<?, ?>> interfaceSenderMap;

    @Value("${ci.synchronizeDevice.pageSize:10}")
    private Integer pageSize;

    @Override
    public QueryStationsInfoResponse send(QueryStationsInfoRequest r, InterworkingConfigDto configDto) {
        String bizSeq = ThreadContext.get(LogTrace.TRACE_ID);

        InterworkingConfig interworkingConfig = configDto.getInterworkingConfig();
        String operatorId = interworkingConfig.getOperatorId();

        String scheduleRedisKey = "synchronizeDeviceSchedule:" + operatorId;
        SynchronizeDeviceSchedule deviceSchedule = synchronizeDeviceScheduleRedisTemplate.opsForValue().get(scheduleRedisKey);
        if (Objects.nonNull(deviceSchedule) && !deviceSchedule.getIsDone()) {
            throw new BusinessException(500, "当前已有正在同步的任务");
        }

        // 同步进度条
        AtomicInteger currentIndex = new AtomicInteger(1);
        int currentPage = 1;
        Long totalSize = 0L;
        SynchronizeDeviceSchedule synchronizeDeviceSchedule = new SynchronizeDeviceSchedule(currentIndex.get(), Integer.MAX_VALUE);
        synchronizeDeviceScheduleRedisTemplate.opsForValue().set(scheduleRedisKey, synchronizeDeviceSchedule);

        // 查询已有的站点
        Set<String> existStationNumber = new HashSet<>();
        List<Station> existStations = stationMapper.selectByInterworkingId(interworkingConfig.getId());
        if (CollectionUtil.isNotEmpty(existStations)) {
            existStationNumber.addAll(existStations.stream().map(Station::getStationNumber).collect(Collectors.toList()));
        }

        Set<String> deletedStationNumber = new HashSet<>();
        Set<String> addStationNumber = new HashSet<>();
        Set<String> updateStationNumber = new HashSet<>();

        QueryStationsInfoRequest request = new QueryStationsInfoRequest();
        InterfaceSender<QueryStationsInfoRequest, QueryStationsInfoResponse> queryStationsInfoService = this.getInterfaceSender(interworkingConfig.getVersion(), MethodEnum.QUERY_STATIONS_INFO);
        InterfaceSender<QueryEquipBusinessPolicyRequest, QueryEquipBusinessPolicyResponse> queryEquipBusinessPolicyService = this.getInterfaceSender(interworkingConfig.getVersion(), MethodEnum.QUERY_EQUIP_BUSINESS_POLICY);
        while (true) {
            request.setPageNo(currentPage);
            request.setPageSize(pageSize);


            QueryStationsInfoResponse stationsInfoResponse = queryStationsInfoService.send(request, configDto);
            logService.log(bizSeq, Constant.Log.SYNCHRONIZE_DEVICE_QUERY, request, stationsInfoResponse, stationsInfoResponse != null);

            if (Objects.isNull(stationsInfoResponse)) {
                log.info("拉取设备信息为空");
                break;
            }

            Long pageCount = stationsInfoResponse.getPageCount();
            Long itemSize = stationsInfoResponse.getItemSize();
            totalSize = itemSize;
            List<StationInfo> stationInfos = stationsInfoResponse.getStationInfos();
            if (CollectionUtil.isEmpty(stationInfos)) {
                break;
            }
            stationInfos.forEach(stationInfo -> {
                try {
                    // 判断是新增/修改/删除
                    String stationId = stationInfo.getStationId();
                    deletedStationNumber.add(stationId);
                    if (CollectionUtil.isEmpty(existStationNumber)) {
                        addStationNumber.add(stationId);
                    } else {
                        if (existStationNumber.contains(stationId)) {
                            updateStationNumber.add(stationId);
                        } else {
                            addStationNumber.add(stationId);
                        }
                    }

                    // 重新组装站点信息
                    SynchronizeDeviceData synchronizeDeviceData = new SynchronizeDeviceData(interworkingConfig.getVersion());
                    BeanUtil.copyProperties(stationInfo, synchronizeDeviceData);
                    List<SynchronizeDeviceEquipmentData> synchronizeDeviceEquipmentDataList = new ArrayList<>();

                    // 遍历桩信息，并重新封装
                    List<EquipmentInfo> equipmentInfos = stationInfo.getEquipmentInfos();
                    if (CollectionUtil.isNotEmpty(equipmentInfos)) {
                        equipmentInfos.forEach(equipmentInfo -> {
                            // 重新组织桩信息
                            SynchronizeDeviceEquipmentData synchronizeDeviceEquipmentData = new SynchronizeDeviceEquipmentData();
                            BeanUtil.copyProperties(equipmentInfo, synchronizeDeviceEquipmentData);
                            List<SynchronizeDeviceConnectorData> synchronizeDeviceConnectorDataList = new ArrayList<>();

                            // 遍历充电枪信息，并查询计费，重新封装
                            List<ConnectorInfo> connectorInfos = equipmentInfo.getConnectorInfos();
                            if (CollectionUtil.isNotEmpty(connectorInfos)) {
                                connectorInfos.forEach(connectorInfo -> {
                                    // 重新组装充电枪和计费信息
                                    SynchronizeDeviceConnectorData synchronizeDeviceConnectorData = new SynchronizeDeviceConnectorData();
                                    BeanUtil.copyProperties(connectorInfo, synchronizeDeviceConnectorData);

                                    QueryEquipBusinessPolicyRequest queryEquipBusinessPolicyRequest = new QueryEquipBusinessPolicyRequest();
                                    queryEquipBusinessPolicyRequest.setEquipBizSeq(interworkingConfig.getOwnerId() + bizSeq);
                                    queryEquipBusinessPolicyRequest.setConnectorId(connectorInfo.getConnectorId());

                                    QueryEquipBusinessPolicyResponse queryEquipBusinessPolicyResponse = queryEquipBusinessPolicyService.send(queryEquipBusinessPolicyRequest, configDto);

                                    synchronizeDeviceConnectorData.setQueryEquipBusinessPolicyResponse(queryEquipBusinessPolicyResponse);
                                    synchronizeDeviceConnectorDataList.add(synchronizeDeviceConnectorData);
                                });
                            }

                            synchronizeDeviceEquipmentData.setConnectorInfos(synchronizeDeviceConnectorDataList);
                            synchronizeDeviceEquipmentDataList.add(synchronizeDeviceEquipmentData);
                        });
                    }

                    synchronizeDeviceData.setEquipmentInfos(synchronizeDeviceEquipmentDataList);
                    boolean sendDeviceInfoMessage = messageChannel.sendDeviceInfoMessage(synchronizeDeviceData);
                    // 同步进度条
                    SynchronizeDeviceSchedule synchronizeDeviceSchedule2 = new SynchronizeDeviceSchedule(currentIndex.get(), itemSize.intValue());
                    synchronizeDeviceScheduleRedisTemplate.opsForValue().set(scheduleRedisKey, synchronizeDeviceSchedule2);
                    currentIndex.getAndIncrement();

                    // 日志
                    logService.log(bizSeq, Constant.Log.SYNCHRONIZE_DEVICE_HANDLE, null, synchronizeDeviceData, sendDeviceInfoMessage);
                } catch (Exception e) {
                    log.error("同步设备出错", e);
                    logService.log(bizSeq, Constant.Log.SYNCHRONIZE_DEVICE_HANDLE, null, e.getMessage(), false);
                }
            });
            if (currentPage >= pageCount) {
                break;
            }
            currentPage++;
        }

        // 同步进度条
        synchronizeDeviceSchedule = new SynchronizeDeviceSchedule(currentIndex.get(), totalSize.intValue(), true, "完成");
        synchronizeDeviceScheduleRedisTemplate.opsForValue().set(scheduleRedisKey, synchronizeDeviceSchedule);

        if (CollectionUtil.isNotEmpty(existStationNumber)) {
            deletedStationNumber.removeAll(existStationNumber);
        }

        log.info("addStationNumber:{}", addStationNumber);
        log.info("updateStationNumber:{}", updateStationNumber);
        log.info("deletedStationNumber:{}", deletedStationNumber);

        return null;
    }

    private InterfaceSender getInterfaceSender(String version, MethodEnum methodEnum) {
        String serviceSuffix = VersionEnum.getServiceSuffix(version);
        String method = methodEnum.getMethod();
        String serviceName = StrUtil.toCamelCase(method) + serviceSuffix + Constant.ServiceSuffix.SENDER_SERVICE;
        InterfaceSender<?, ?> interfaceSender = interfaceSenderMap.get(serviceName);
        Assert.notNull(interfaceSender, () -> {
            throw new BusinessException(500, "根据" + serviceName + "找不到实现类");
        });
        return interfaceSender;
    }
}
